package cn.wecloud.im.multiplayervideodemo.rtc

import android.content.Context
import android.util.Log
import cn.wecloud.im.core.im.messages.Command
import cn.wecloud.im.multiplayervideodemo.App
import cn.wecloud.im.multiplayervideodemo.R
import org.webrtc.*
import org.webrtc.voiceengine.WebRtcAudioManager
import org.webrtc.voiceengine.WebRtcAudioUtils
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

class VideoChatHelper(
    private val mContext: Context,
    private val rtcType: Int,
    private val eglBaseContext: EglBase.Context?,
) {

    companion object {
        const val TAG = "VideoChatHelper"
        private const val VIDEO_TRACK_ID = "ARDAMSv0"
        private const val AUDIO_TRACK_ID = "ARDAMSa0"

        //视频宽
        private const val videoWidth: Int = 640

        //视频高
        private const val videoHeight: Int = 360

        //视频帧率
        private const val videoFps: Int = 15

    }

    var isFront: Boolean = false
    var isFull: Boolean = true
    var peerConnection: PeerConnection? = null
    var remoteProxyRenderer: ProxyRenderer? = null
        get() {
            if (field == null) {
                field = ProxyRenderer()
            }
            return field
        }
    var localProxyRenderer: ProxyRenderer? = null
        get() {
            if (field == null) {
                field = ProxyRenderer()
            }
            return field
        }

    //ICEServer
    private val iceServers: List<PeerConnection.IceServer> by lazy {
        val servers = LinkedList<PeerConnection.IceServer>()
        val iceServer1 =
            PeerConnection.IceServer.builder(arrayListOf("stun:stun1.l.google.com:19302"))
                .createIceServer()
        servers.add(iceServer1)
        val iceServer4 = PeerConnection.IceServer.builder("turn:120.55.49.33")
            .setUsername("xiaolandou")
            .setPassword("xiaolandou")
            .createIceServer()
        val iceServer6 = PeerConnection.IceServer.builder("stun:120.55.49.33").createIceServer()
        val iceServer8 = PeerConnection.IceServer.builder("stun:139.9.216.85").createIceServer()
        val iceServer9 = PeerConnection.IceServer.builder("turn:139.9.216.85")
            .setUsername("xiaolandou")
            .setPassword("xiaolandou")
            .createIceServer()
        servers.add(iceServer4)
        servers.add(iceServer6)
        servers.add(iceServer8)
        servers.add(iceServer9)
        servers
    }

    //sdp对等约束
    val sdpMediaConstraints: MediaConstraints by lazy {
        val mediaConstraints = MediaConstraints()
        mediaConstraints.mandatory.add(MediaConstraints.KeyValuePair("iceRestart", "true"))
        mediaConstraints.mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true"))
        if (videoCallEnabled) {
            mediaConstraints.mandatory.add(
                MediaConstraints.KeyValuePair("OfferToReceiveVideo", "true")
            )
        } else {
            mediaConstraints.mandatory.add(
                MediaConstraints.KeyValuePair("OfferToReceiveVideo", "false")
            )
        }
        mediaConstraints
    }


    private val executor: ExecutorService by lazy {
        Executors.newSingleThreadExecutor()
    }
    private var factory: PeerConnectionFactory? = null

    //是否开启视频
    private var videoCallEnabled: Boolean = rtcType == Command.WeRtcType.RTC_TYPE_VIDEO.code

    // 本地音视频流
    private var videoRenderVideo: Boolean = true
    private var localMediaStream: MediaStream? = null
    private var videoSource: VideoSource? = null
    private var videoCapturer: VideoCapturer? = null
    private var surfaceTextureHelper: SurfaceTextureHelper? = null
    private var remoteVideoTrack: VideoTrack? = null
    private var localVideoTrack: VideoTrack? = null
        get() {
            if (field == null) {
                if (videoSource == null) {
                    if (videoCapturer == null) {
                        videoCapturer = createVideoCapturer()
                    }
                    if (videoCapturer == null) {//如果没有摄像头就禁用视频通话
                        videoCallEnabled = false
                    }
                    if (!videoCallEnabled) {
                        return null
                    }
                    if (surfaceTextureHelper == null) {
                        surfaceTextureHelper =
                            SurfaceTextureHelper.create("CaptureThread", eglBaseContext)
                    }
                    videoSource = factory?.createVideoSource(false)
                    videoCapturer?.initialize(
                        surfaceTextureHelper,
                        mContext,
                        videoSource?.capturerObserver
                    )
                    videoCapturer?.startCapture(videoWidth, videoHeight, videoFps)
                }
                field = factory?.createVideoTrack(VIDEO_TRACK_ID, videoSource)
                field?.setEnabled(videoRenderVideo)
                field?.addSink(localProxyRenderer)
//                callBack.swapped(cameraInfo)
            }
            return field
        }


    //音频控制开关
    private var enableAudio: Boolean = true

    //音频约束
    private val audioConstraints: MediaConstraints by lazy {
        val constraints = MediaConstraints()
        constraints
    }
    private var audioSource: AudioSource? = null

    //音轨
    private var localAudioTrack: AudioTrack? = null
        get() {
            if (field == null) {
                if (audioSource == null) {
                    audioSource = factory?.createAudioSource(audioConstraints)
                }
                field = factory?.createAudioTrack(AUDIO_TRACK_ID, audioSource)
                field?.setEnabled(enableAudio)
            }
            return field
        }

    //初始化工厂与本地音视频流
    fun initPeerAndLocalStream() {
        WebRtcAudioManager.setBlacklistDeviceForOpenSLESUsage(false)
        WebRtcAudioUtils.setWebRtcBasedAcousticEchoCanceler(false)
        WebRtcAudioUtils.setWebRtcBasedAutomaticGainControl(false)
        WebRtcAudioUtils.setWebRtcBasedNoiseSuppressor(false)
        PeerConnectionFactory.initialize(
            PeerConnectionFactory
                .InitializationOptions
                .builder(mContext)
                .createInitializationOptions()
        )
        val encoderFactory = DefaultVideoEncoderFactory(
            eglBaseContext,
            true /* enableIntelVp8Encoder */,
            false/*enableH264HighProfile*/
        )
        val decoderFactory = DefaultVideoDecoderFactory(eglBaseContext)
        if (factory == null) {
            factory = PeerConnectionFactory.builder()
                .setVideoEncoderFactory(encoderFactory)
                .setVideoDecoderFactory(decoderFactory)
                .createPeerConnectionFactory()
        }
        if (localMediaStream == null) {
            createLocalStream()
        }
    }


    /*
    * 创建本地流
    * */
    private fun createLocalStream() {
        localMediaStream = null
        localMediaStream = factory?.createLocalMediaStream("ARDAMS")
        // 视频
        if (videoCallEnabled) {
            if (localVideoTrack != null) {
                localMediaStream?.addTrack(localVideoTrack)
            }
        }
        // 音频
        localMediaStream?.addTrack(localAudioTrack)

    }

    private fun createVideoCapturer(): VideoCapturer? {
        val enumerator: CameraEnumerator? = /*if (Camera2Enumerator.isSupported(mContext)) {
            Camera2Enumerator(mContext)
        } else {*/
            Camera1Enumerator(true)
//        }
        val deviceNames = enumerator?.deviceNames
        deviceNames?.forEach {
            if (enumerator.isFrontFacing(it)) {
                val createCapturer = enumerator.createCapturer(it, null)
                if (createCapturer != null) {
                    isFront = true
                    return createCapturer
                }
            }
        }
        deviceNames?.forEach {
            if (!enumerator.isFrontFacing(it)) {
                val capturer = enumerator.createCapturer(it, null)
                if (capturer != null) {
                    isFront = false
                    return capturer
                }
            }
        }
        return null
    }

    /**
     * 设置本地音轨是否启用
     * false 静音
     */
    fun setAudioEnabled(isAudioEnable: Boolean) {
        executor.execute {
            try {
                Log.e(TAG, "setAudioEnabled: $isAudioEnable")
                enableAudio = isAudioEnable
                localAudioTrack?.setEnabled(enableAudio)
            } catch (e: Exception) {

            }
        }
    }


    var isSwitchCamera = false
    fun switchCameraInternal(callback: ((Boolean, String?) -> Unit)) {
        executor.execute {
            if (isSwitchCamera) {
                return@execute
            }
            isSwitchCamera = true
            if (videoCapturer is CameraVideoCapturer) {
                if (!videoCallEnabled || videoCapturer == null) {
                    callback(false, App.instance.getString(R.string.no_camera_detected))
                    return@execute
                }
                isFront = !isFront
                val cameraVideoCapturer = videoCapturer as CameraVideoCapturer
                cameraVideoCapturer.switchCamera(object : CameraVideoCapturer.CameraSwitchHandler {
                    override fun onCameraSwitchDone(p0: Boolean) {
                        isSwitchCamera = false
                    }

                    override fun onCameraSwitchError(p0: String?) {
                        isSwitchCamera = false
                    }

                })
                callback(true,"")
            } else {
                callback(false, App.instance.getString(R.string.no_camera_detected))
            }
        }
    }

    fun addIceCandidate(iceCandidate: IceCandidate?) {
        peerConnection?.addIceCandidate(iceCandidate)
    }

    //创建并设置本地offer
    fun createLocalOffer(callback: ((SessionDescription?, Boolean) -> Unit)) {
        peerConnection?.createOffer(object : SdpObserver {
            var sdp: SessionDescription? = null
            override fun onCreateSuccess(sessionDescription: SessionDescription) {
                sdp = sessionDescription
                peerConnection?.setLocalDescription(this, sdp)
            }

            override fun onCreateFailure(s: String) {
                callback.invoke(null, false)
            }

            override fun onSetSuccess() {
                callback.invoke(sdp, true)
            }

            override fun onSetFailure(s: String) {
                callback.invoke(null, false)
            }
        }, sdpMediaConstraints)
    }

    //设置远程offer，
    fun setRemoteDescription(
        sdp: SessionDescription, callback: ((SessionDescription?, Boolean) -> Unit)
    ) {
        peerConnection?.setRemoteDescription(object : SdpObserver {
            var answer: SessionDescription? = null
            override fun onSetSuccess() {
                Log.e(TAG, "onSetSuccess: ${peerConnection?.signalingState()}")
                when (peerConnection?.signalingState()) {
                    PeerConnection.SignalingState.HAVE_REMOTE_OFFER -> {
                        //设置了远程offer
                        peerConnection?.createAnswer(this, sdpMediaConstraints)
                    }
                    PeerConnection.SignalingState.HAVE_LOCAL_PRANSWER -> {
                        //设置的本地的answer
                        callback(answer, true)
                    }
                    PeerConnection.SignalingState.HAVE_REMOTE_PRANSWER -> {
                        //设置了远程answer
                        callback(null, true)
                    }
                    PeerConnection.SignalingState.STABLE -> {
                        //设置了远程answer
                        callback(answer, true)
                    }
                    else -> {
                        Log.e(TAG, "onSetSuccess: ${peerConnection?.signalingState()}")
                    }
                }
            }

            override fun onCreateSuccess(sessionDescription: SessionDescription) {
                Log.e(TAG, "onCreateSuccess: ${sessionDescription.type}")
                answer = sessionDescription
                peerConnection?.setLocalDescription(this, answer)
            }

            override fun onCreateFailure(s: String) {
                Log.e(TAG, "onCreateFailure: $s")
                callback(null, false)
            }

            override fun onSetFailure(s: String) {
                Log.e(TAG, "onSetFailure: $s")
                callback(null, false)
            }
        }, sdp)
    }

    fun onStart() {
        Log.e(TAG, "onStart")
        executor.execute {
            if (videoCallEnabled) {
                localVideoTrack?.setEnabled(true)
                videoCapturer?.startCapture(videoWidth, videoHeight, videoFps)
            }
            addStream()
        }
    }

    private fun addStream() {
        if (localMediaStream == null) {
            Log.e(TAG, "添加本地流时，本地流为空")
        } else {
            try {
                peerConnection?.addStream(localMediaStream)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    fun cteatelPeer(clientId: String, callback: (IceCandidate?) -> Unit) {
        peerConnection = createPeerConnection(object : PeerConnectionAdapter(clientId) {

            override fun onIceCandidate(iceCandidate: IceCandidate) {
                super.onIceCandidate(iceCandidate)
                Log.e(TAG, "onIceCandidate已执行")
                callback(iceCandidate)
            }

            override fun onAddStream(mediaStream: MediaStream) {
                super.onAddStream(mediaStream)
                Log.e(TAG, "onAddStream已执行")
                executor.execute {
                    mediaStream.audioTracks?.forEach {
                        it.setEnabled(true)
                    }
                    when {
                        mediaStream.audioTracks?.size ?: 0 > 1 || mediaStream.videoTracks?.size ?: 0 > 1 -> {
                            Log.d(TAG, "Weird-looking steam:$mediaStream")
                        }
                        mediaStream.videoTracks?.size == 1 -> {
                            remoteVideoTrack = mediaStream.videoTracks[0]
                            remoteVideoTrack?.setEnabled(videoRenderVideo)
                            remoteVideoTrack?.addSink(remoteProxyRenderer)
                            Log.e(TAG, "onAddStream videoTracks已执行")
                        }
                        mediaStream.audioTracks?.size == 1 -> {
                            Log.e(TAG, "onAddStream audioTracks已执行")
                            val audioTrack = mediaStream.audioTracks[0]
                            audioTrack.setEnabled(true)
                        }
                        else -> {
                        }
                    }
                }
            }

        })
    }


    private fun createPeerConnection(observer: PeerConnection.Observer): PeerConnection? {
        var createPeerConnection: PeerConnection? = null
        try {
            val rtcConfig = PeerConnection.RTCConfiguration(iceServers)
//             只有连接到支持的服务器时，TCP候选项才有用
//             ICE-TCP.
//        rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED
//        rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE
//        rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE
//        rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY
            // Use ECDSA encryption.
//        rtcConfig.keyType = PeerConnection.KeyType.ECDSA
            // Enable DTLS for normal calls and disable for loopback calls.
//        rtcConfig.enableDtlsSrtp = true
//        rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN
            createPeerConnection = factory?.createPeerConnection(rtcConfig, observer)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return createPeerConnection
    }

    fun disconnect() {
        remoteProxyRenderer?.setTarget(null)
        localProxyRenderer?.setTarget(null)
        executor.execute {
            closeInternal()
        }
    }


    private fun closeInternal() {
        try {
            peerConnection?.dispose()
        } catch (e: Exception) {
            e.printStackTrace()
        }

        audioSource?.dispose()
        audioSource = null
        try {
            videoCapturer?.stopCapture()
        } catch (e: InterruptedException) {
            throw RuntimeException(e)
        }
        videoCapturer?.dispose()
        videoCapturer = null
        videoSource?.dispose()
        videoSource = null
        surfaceTextureHelper?.dispose()
        surfaceTextureHelper = null
//        localMediaStream?.dispose()
        localMediaStream = null
        localProxyRenderer = null
        if (factory != null) {
            factory?.dispose()
            factory = null
        }
    }

}